import {D} from "../data/getdata.js"
import API from "../../http/api.js"
import attrsCheck from "../../general/attrsCheck.js"
import vNode from "../structs/render_vNode.js"
import async from "../../general/async.js"

function c() {
    this.context = undefined
    this.layout = undefined
    this.nodes = undefined
    this.childSource = []
}

c.prototype = new async()
c.prototype.constructor = c

/**make
 * get an config to make virtual nodes.
 * config see more: HELP_COMPILE_CONFIG_FILE.md
 * @param {*} cfgURI config file uri.
 * @param {*} context compile instance.
 */
c.prototype.make = function (cfgURI, context = undefined) {
    this.context = context;
    this.target = this
    cfgURI += cfgURI.indexOf('?') > -1 ? "&timestamp=" : "?timestamp=" + Date.parse(new Date()).toString();
    (function (uri, self) {
        ++self.waitTask;
        API.getContext(uri).then((response) => {
            (new attrsCheck(response.data, ['dataSet', 'layout'])).then((data) => {
                self.layout = data.layout;
                (function (self) {
                    // merge vue constructor methods prototype.
                    if ("layout" in self) {
                        if ('mount' in self.layout) {
                            if ('func' in self.layout.mount) {
                                if (self.context !== undefined) {
                                    if (!('layout' in self.context)) {
                                        self.context['layout'] = {}
                                    } if (!('mount' in self.context.layout)) {
                                        self.context.layout['mount'] = {}
                                    } if (!('func' in self.context.layout.mount)) {
                                        self.context.layout.mount['func'] = {}
                                    }
                                }
                                for (let o in data.layout.mount.func) {
                                    self.target.layout.mount.func[o] = data.layout.mount.func[o]
                                    if (self.context !== undefined) {
                                        self.context.layout.mount.func[o] = data.layout.mount.func[o]
                                    }
                                }
                            }
                        }
                    }
                })(self);
                // auto generate data by model cfg.
                (new D()).create(data.dataSet).asyncThen((data) => {
                    //console.log(data)
                    self.nodes = self.initInstance(data);
                }, (error) => {
                    throw error;
                });
            }).catch((error) => {
                throw error
            });
        }).catch((error) => {
            throw error
        });
    })(cfgURI, this);
    return this
}

c.prototype.initInstance = function (data) {
    //merge vue constructor data and pros prototype.
    if (Object.keys(data).length <= 0) {
        if (this.context != undefined) {
            if ('data' in this.context) {
                this.target['data'] = this.context.data
            }
        }
    }
    if (!('data' in this.target)) {
        this.target['data'] = {}
    }
    if (this.context !== undefined) {
        if (!('data' in this.context)) {
            this.context['data'] = {}
        }
    }
    for (let o in data) {
        this.target.data[o] = data[o]
        if (this.context !== undefined) {
            this.context.data[o] = data[o];
        }
    }
    let _nodes = this.createVnode(this.layout.nodes);
    --this.waitTask;
    return _nodes;//target.createVnode(target.layout.nodes, target);
}

c.prototype.createVnode = function (cfg, target = undefined) {
    ++this.waitTask;
    if (this.context !== undefined) {
        ++this.context.waitTask;
    }
    let v_node = undefined
    if (typeof (cfg) == "string") {
        cfg = JSON.parse(cfg)
    }
    if ("source" in cfg) {
        (new c()).make(cfg.source, this.context !== undefined ? this.context.target : this.target).asyncThen((data) => {
            //console.log(cfg.source);
            //console.log(data)
            //console.log("------------------------")

            target.appendChildNode(data.nodes);
            --this.waitTask;
            if (this.context !== undefined) {
                --this.context.waitTask;
            }
        })
    } else {
        switch (typeof (cfg)) {
            case "object": {
                if (Array.isArray(cfg)) {
                    cfg.forEach(o => {
                        v_node = new vNode(o.el, o.attributes)
                        if ('childs' in o) {
                            for (let child in o.childs) {
                                if (typeof (o.childs[child]) != 'string') {
                                    if ("source" in o.childs[child]) {
                                        this.createVnode(o.childs[child], v_node)
                                    } else {
                                        v_node.appendChildNode(this.createVnode(o.childs[child]))
                                    }
                                }
                                else {
                                    v_node.setValue(o.childs[child])
                                }
                            }
                        }
                        if ('text' in o) {
                            v_node.setValue(o.text)
                        }
                        if ('data' in o) {
                            if (typeof (o.data) === "string") {
                                v_node.setDataSource(o.data)
                                
                                if (o.data.indexOf('self.') > -1) {
                                    let propsData = "props_" + o.data.replace('self.', "")
                                    let dataData = "data_" + o.data.replace('self.', "")
                                    if (propsData in this.target['data']) {
                                        v_node.setDataSource(Reflect.get(this.target['data'], propsData))
                                    }
                                    else {
                                        if (dataData in this.target['data']) {
                                            v_node.setDataSource(Reflect.get(this.target['data'], dataData))
                                        } else {
                                            if (o.data.replace('self.', '') in this.target['data']) {
                                                v_node.setDataSource(Reflect.get(this.target['data'], o.data.replace('self.', '')))
                                            }
                                            else {
                                                v_node.setDataSource(o.data)
                                            }
                                        }
                                    }
                                } else {
                                    v_node.setDataSource(o.data)
                                }
                            } else {
                                v_node.setDataSource(o.data)
                            }
                        }
                    })
                    //--this.waitTask;
                    //--context.waitTask;
                    --this.waitTask;
                    if (this.context !== undefined) {
                        --this.context.waitTask;
                    }
                    return v_node
                }
                else {
                    v_node = new vNode(cfg.el, cfg.attributes)
                    if ('childs' in cfg) {
                        for (let child in cfg.childs) {
                            if (typeof (cfg.childs[child]) != 'string') {
                                if ("source" in cfg.childs[child]) {
                                    this.createVnode(cfg.childs[child], v_node)
                                } else {
                                    v_node.appendChildNode(this.createVnode(cfg.childs[child]))
                                }
                            }
                            else {
                                v_node.setValue(cfg.childs[child])
                            }
                        }
                    }
                    if ('text' in cfg) {
                        v_node.setValue(cfg.text)
                    }
                    if ('data' in cfg) {
                        if (typeof (cfg.data) === "string") {
                            if (cfg.data.indexOf('self.') > -1) {
                                
                                let propsData = "props_" + cfg.data.replace('self.', "")
                                let dataData = "data_" + cfg.data.replace('self.', "")
                                if (propsData in this.target['data']) {
                                    v_node.setDataSource(Reflect.get(this.target['data'], propsData))
                                }
                                else {
                                    if (dataData in this.target['data']) {
                                        v_node.setDataSource(Reflect.get(this.target['data'], dataData))
                                    } else {
                                        if (cfg.data.replace('self.', '') in this.target['data']) {
                                            v_node.setDataSource(Reflect.get(this.target['data'], cfg.data.replace('self.', '')))
                                        }
                                        else {
                                            v_node.setDataSource(cfg.data)
                                        }
                                    }
                                }
                                v_node.setDataSource(cfg.data)
                            }
                            else {
                                v_node.setDataSource(cfg.data)
                            }
                        } else {
                            v_node.setDataSource(cfg.data)
                        }
                    }
                    //--this.waitTask;
                    //--context.waitTask;
                    --this.waitTask;
                    if (this.context !== undefined) {
                        --this.context.waitTask;
                    }
                    return v_node
                }
            }
        }
    }
}

const compile = new c()

export default compile